#import "MRCollectionViewLayout.h"
#import "MRCollectionView.h"

@interface MRCollectionViewLayout ()
{
	NSUInteger  _count;
}

@property (nonatomic) UIEdgeInsets					sectionInset;		//调整边距

@end

@implementation MRCollectionViewLayout

+ (instancetype)layoutWithStyle:(MRCollectionViewLayoutStyle)style
{
	return [[MRCollectionViewLayout alloc] initWithStyle:style];
}

- (instancetype)init
{
	return [self initWithStyle:MRCollectionViewLayoutStyleDefault];
}

- (instancetype)initWithStyle:(MRCollectionViewLayoutStyle)style
{
    if (self = [super init])
	{
		[self awakeFromNib];
        self.style = style;
    }
	
    return self;
}

- (void)awakeFromNib
{
	[super awakeFromNib];
	
	self.centerOffset = .5;
	self.itemDistance = 300;
	self.itemControl  = self.itemScale = self.itemAlpha = 1;
	self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
}

/*===================================================================
 说明:
	内容边距
 ==================================================================*/
- (void)prepareLayout
{
    [super prepareLayout];
	
	CGSize size = self.collectionView.bounds.size;
	UIEdgeInsets contentInset = UIEdgeInsetsZero;
	
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
	{
		contentInset.top = contentInset.bottom = (size.height - self.itemSize.height) / 2;
    }
	else
	{
		contentInset.left = contentInset.right = (size.width - self.itemSize.width) / 2;
    }
	
	self.sectionInset = contentInset;
}

/*===================================================================
 说明:
	内容大小
 ==================================================================*/
- (CGSize)collectionViewContentSize
{
	CGSize size = CGSizeMake(self.sectionInset.left + self.sectionInset.right, self.sectionInset.top + self.sectionInset.bottom);
	
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
		size.height += [self.collectionView numberOfItemsInSection:0] * self.itemSize.height;
	else
		size.width += [self.collectionView numberOfItemsInSection:0] * self.itemSize.width;
	
    return size;
}

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
	return !CGRectEqualToRect(newBounds, self.collectionView.bounds);
}

#pragma mark - 单元格属性
/*===================================================================
 说明:
	调整单元格属性
 ==================================================================*/
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSInteger count = [self.collectionView numberOfItemsInSection:0];	//单元格总数
	if (!count) return nil;
	
	//中间单元格索引
    NSInteger midIndex;
	if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
		midIndex = (self.collectionView.contentOffset.y + self.itemSize.height / 2) / self.itemSize.height;
	else
		midIndex = (self.collectionView.contentOffset.x + self.itemSize.width / 2) / self.itemSize.width;
	
	//获取可见单元格的布局属性
	NSInteger minIndex = self.visibleCount < 1 ? 0 : MAX(0, (midIndex - self.visibleCount / 2));
	NSInteger maxIndex = self.visibleCount < 1 ? count : MIN(count, (midIndex + self.visibleCount / 2));
	
	NSMutableArray *array = [NSMutableArray array];
    for (NSInteger i=minIndex; i<maxIndex; i++)
	{
		UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        [array addObject:attr];
    }
	
    return array;
}

/*===================================================================
 说明:
	单元格属性
 ==================================================================*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
	UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
	
	CGSize size = self.itemSize;
	CGPoint center;
	CGFloat offset;
	
	NSInteger middle;
	if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
	{
		center = CGPointMake(self.collectionView.bounds.size.width * self.centerOffset, size.height * (indexPath.row + 0.5) + self.sectionInset.top);
		offset = (center.y - CGRectGetMidY(self.collectionView.bounds)) / size.height;
		middle = (self.collectionView.contentOffset.y + size.height / 2) / size.height;
	}
	else
	{
		center = CGPointMake(size.width * (indexPath.row + 0.5) + self.sectionInset.left, self.collectionView.bounds.size.height * self.centerOffset);
		offset = (center.x - CGRectGetMidX(self.collectionView.bounds)) / size.width;
		middle = (self.collectionView.contentOffset.x + size.width / 2) / size.width;
	}
	
	attr.zIndex = -ABS(middle - indexPath.row);
	
	//透明控制
	if (self.itemAlpha < 1)
	{
		attr.alpha = 1.f - (1.f - self.itemAlpha) * MIN(1.f, ABS(offset) / self.itemControl);
	}
	
	//变换
	CGFloat scale = 1.f;
	CGFloat rotate = 0.f;
	
	switch (self.style)
	{
		case MRCollectionViewLayoutStyleCoverFlow:	//
			
			rotate = offset * M_PI_4 / self.itemControl;
			if (rotate > M_PI_4) rotate = M_PI_4;
			if (rotate < -M_PI_4) rotate = -M_PI_4;
			
			//平移+旋转 (平移为了保证透视旋转后最大边与原始边看上去一样)
			CATransform3D transform = CATransform3DIdentity;
			transform.m34 = -1.f / self.itemDistance;
			
			if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
			{
				CGFloat z = size.height / 2.f * sin(ABS(rotate));
				transform = CATransform3DTranslate(transform, 0, 0, -z);
				attr.transform3D = CATransform3DRotate(transform, rotate, 1, 0, 0);
			}
			else
			{
				CGFloat z = size.width / 2.f * sin(ABS(rotate));
				transform = CATransform3DTranslate(transform, 0, 0, -z);
				attr.transform3D = CATransform3DRotate(transform, rotate, 0, -1, 0);
			}
			break;
		
		case MRCollectionViewLayoutStyleDefault:
		case MRCollectionViewLayoutStyleLinear:		//线性缩放
			
			scale = 1.f - (1.f - self.itemScale) * MIN(1.f, ABS(offset) / self.itemControl);
			attr.transform3D = CATransform3DMakeScale(scale, scale, 1);
			
			if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
				center.x += size.width * (1 - scale) / 2 * self.itemAlign;
			else
				center.y += size.height * (1 - scale) / 2 * self.itemAlign;
			break;
	}
	
	//间距处理
	if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
		center.y -= [self offsetWithTarget:ABS(offset) size:size.height negative:(offset < 0)];
	else
		center.x -= [self offsetWithTarget:ABS(offset) size:size.width negative:(offset < 0)];
	
	//
	attr.size   = CGSizeMake(LOCPIXEL(size.width), LOCPIXEL(size.height));
	attr.center = CGPointMake(LOCPIXEL(center.x), LOCPIXEL(center.y));
	
	return attr;
}

/*===================================================================
 说明:
	计算单元格间隙偏移
 ==================================================================*/
- (CGFloat)offsetWithTarget:(CGFloat)offset size:(CGFloat)size negative:(BOOL)negative
{
	CGFloat target = -self.itemSpacing * offset;
	CGFloat rotate = 0.f;
	CGFloat scale  = 1.f;
	
	BOOL	first = YES;
	
	while (offset)
	{
		switch (self.style)
		{
			case MRCollectionViewLayoutStyleCoverFlow:	//
				rotate = offset * M_PI_4 / self.itemControl;
				if (rotate > M_PI_4) rotate = M_PI_4;
				if (rotate < -M_PI_4) rotate = -M_PI_4;
				
				CGFloat z = size / 2.f * sin(ABS(rotate));
				scale = 1.f - cos(ABS(rotate)) * (self.itemDistance / (z + self.itemDistance));
				break;
				
			case MRCollectionViewLayoutStyleLinear:
				scale = (1.f - self.itemScale) * MIN(1.f, offset / self.itemControl);
				break;
				
			case MRCollectionViewLayoutStyleDefault:
				return (negative ? -self.itemSpacing : self.itemSpacing) * offset;
		}
		
		target += size * scale;
		if (first) {first = NO; target /= 2;}
		
		if (offset >= 1) offset -= 1.f; else offset = 0.f;
	}
	
	return negative ? -target : target;
}

#pragma mark - 单元格管理
/*===================================================================
 说明:
	初始单元格
 ==================================================================*/
- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems
{
	[super prepareForCollectionViewUpdates:updateItems];
	_updateItems = updateItems;
}

/*===================================================================
 说明:
	初始布局
 ==================================================================*/
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
	UICollectionViewLayoutAttributes *attr = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];
	
	for (UICollectionViewUpdateItem *updateItem in _updateItems)
	{
		if (updateItem.updateAction == UICollectionUpdateActionInsert && [updateItem.indexPathAfterUpdate compare:itemIndexPath] == NSOrderedSame)
		{
			//插入时初始属性
			attr.center = CGPointMake(attr.center.x, 0);
			attr.alpha  = 0;
			
			id delegate = self.collectionView.delegate;
			if ([delegate respondsToSelector:@selector(collectionView:initialLayoutAttributes:)])
			{
				[delegate collectionView:self.collectionView initialLayoutAttributes:attr];
			}
			break;
		}
	}
	
	return attr;
}

/*===================================================================
 说明:
	完成布局
 ==================================================================*/
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
	UICollectionViewLayoutAttributes *attr = [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];
	
	for (UICollectionViewUpdateItem *updateItem in _updateItems)
	{
		if (updateItem.updateAction == UICollectionUpdateActionDelete && [updateItem.indexPathBeforeUpdate compare:itemIndexPath] == NSOrderedSame)
		{
			//移除时终止属性
			attr.center = CGPointMake(attr.center.x, 0);
			attr.alpha  = 0;
			
			id delegate = self.collectionView.delegate;
			if ([delegate respondsToSelector:@selector(collectionView:finalLayoutAttributes:)])
			{
				[delegate collectionView:self.collectionView finalLayoutAttributes:attr];
			}
			break;
		}
	}
	
	return attr;
}

#pragma mark -
/*===================================================================
 说明:
	保证单元格居中
 ==================================================================*/
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
	if (self.collectionView.pagingEnabled) return proposedContentOffset;
	
	if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
	{
		NSInteger index = (proposedContentOffset.y + self.itemSize.height / 2) / self.itemSize.height;
        proposedContentOffset.y = self.itemSize.height * index;
    }
	else
	{
		NSInteger index = (proposedContentOffset.x + self.itemSize.width / 2) / self.itemSize.width;
		proposedContentOffset.x = self.itemSize.width * index;
    }
	
    return proposedContentOffset;
}

@end
